package model

import (
	"fmt"
	config "gitee.com/lanshiren/miniprogram/app/conf"
	"strconv"
	"strings"
	"time"
)

const (
	UnderReview          = 1
	FailToPassReview     = 2
	Approved             = 3
	RegistrationDeadline = 4
	ActivityEnd          = 5
	ActivityCancel       = 6
	Unknown
)

const (
	UnderReviewDesc          = "未审核"
	FailToPassReviewDesc     = "审核不通过"
	ApprovedDesc             = "报名中"
	RegistrationDeadlineDesc = "报名已截止"
	ActivityEndDesc          = "活动结束"
	ActivityCancelDesc       = "活动关闭"
	UnknownDesc              = "未知错误"
)

type ActivityDO struct {
	ID                   uint `gorm:"primary_key"`
	UpdatedAt            time.Time
	CreatedAt            time.Time
	Title                string `gorm:"title"`
	StartPlace           string `gorm:"start_place"`
	EndPlace             string `gorm:"end_place"`
	StartTime            int64  `gorm:"start_time"`
	RegistrationDeadline int64  `gorm:"registration_deadline"`
	CollectionPlace      string `gorm:"collection_place"`
	LeaderID             uint   `gorm:"leader_id"`
	LeaderSay            string `gorm:"leader_say"`
	RouteDesc            string `gorm:"route_desc"`
	RoutePics            string `gorm:"route_pics"`
	Attention            string `gorm:"attention"`
	CurCount             int    `gorm:"cur_count"`
	CountLimit           int    `gorm:"count_limit"`
	RouteId              int    `gorm:"route_id"`
	QrCode               string `gorm:"qr_code"`
	Status               int    `gorm:"status"`
}

type VerifyActivityParam struct {
	ID        uint `json:"id"`
	IsApprove bool `json:"is_approve"`
}

type UpdateActivityParam struct {
	ID       uint       `json:"id"`
	IsCancel bool       `json:"is_cancel"`
	Activity ActivityVO `json:"activity"`
}

type ActionRes struct {
	Action string `json:"action"`
	Text   string `json:"text"`
}

type ActivityVO struct {
	ID                   uint         `json:"id"`
	Title                string       `json:"title"`
	StartPlace           string       `json:"start_place"`
	EndPlace             string       `json:"end_place"`
	StartTime            int64        `json:"start_time"`
	RegistrationDeadline int64        `json:"registration_deadline"`
	CollectionPlace      string       `json:"collection_place"`
	LeaderID             uint         `json:"leader_id"`
	LeaderName           string       `json:"leader_name"`
	Phone                string       `json:"phone"`
	LeaderSay            string       `json:"leader_say"`
	RouteDesc            string       `json:"route_desc"`
	RoutePics            string       `json:"route_pics"`
	Attention            string       `json:"attention"`
	CurCount             int          `json:"cur_count"`
	CountLimit           int          `json:"count_limit"`
	QrCode               string       `json:"qr_code"`
	Status               int          `json:"status"`
	StatusDesc           string       `json:"status_desc"`
	ActionList           []*ActionRes `json:"action_list"`
	AvatarUrls           []string     `json:"avatar_urls"`
}

type FetchActivityParam struct {
	ID int `json:"id" form:"id"`
}

type SearchActivitiesParam struct {
	Page                 string `json:"page" form:"page"`
	PageSize             string `json:"pagesize" form:"pagesize"`
	LeaderID             uint   `json:"leader_id" form:"leader_id"`
	UserID               uint   `json:"user_id" form:"user_id"`
	Status               uint   `json:"status" form:"status"`
	ID                   int    `json:"id" form:"id"`
	Title                string `json:"title" form:"title"`
	StartTime            string `json:"start_time" form:"start_time"`
	RegistrationDeadline string `json:"registration_deadline" form:"registration_deadline"`
	CollectionPlace      string `json:"collection_place" form:"collection_place"`
	LeaderName           string `json:"leader_name" form:"leader_name"`
}

func (ActivityDO) TableName() string {
	return "activities"
}

func CreateActivity(ac *ActivityDO) error {
	db := config.GetDB()
	return db.Create(ac).Error
}

func GetActivity(ac *ActivityDO) error {
	db := config.GetDB()
	if err := db.First(&ac, ac.ID).Error; err != nil {
		return err
	}
	return nil
}

// SearchActivityList ...
func SearchActivityList(param SearchActivitiesParam) (total int, activities []*ActivityDO, err error) {
	db := config.GetDB()
	page, err := strconv.Atoi(param.Page)
	if err != nil {
		return 0, nil, err
	}
	pageSize, err := strconv.Atoi(param.PageSize)
	if err != nil {
		return 0, nil, err
	}
	offset := page * pageSize
	limit := param.PageSize

	clauseKeys := []string{}
	clauseValues := []interface{}{}

	if param.ID != 0 {
		clauseKeys = append(clauseKeys, "activities.id LIKE ?")
		clauseValues = append(clauseValues, fmt.Sprintf(`%%%d%%`, param.ID))
	}
	if len(param.Title) != 0 {
		clauseKeys = append(clauseKeys, "activities.title LIKE ?")
		clauseValues = append(clauseValues, fmt.Sprintf(`%%%s%%`, param.Title))
	}
	if len(param.CollectionPlace) != 0 {
		clauseKeys = append(clauseKeys, "activities.collection_place LIKE ?")
		clauseValues = append(clauseValues, fmt.Sprintf(`%%%s%%`, param.CollectionPlace))
	}
	if param.UserID != 0 {
		clauseKeys = append(clauseKeys, "registration.user_id = ?")
		clauseValues = append(clauseValues, param.UserID)
	}

	if len(clauseKeys) > 0 {
		err := db.Table("activities").Select("activities.*").
			Joins("LEFT JOIN registration ON activities.id = registration.activity_id").
			Where(strings.Join(clauseKeys, " AND "), clauseValues...).Count(&total).Error
		if err != nil {
			return total, nil, err
		}
		err = db.Table("activities").Select("activities.*").
			Joins("LEFT JOIN registration ON activities.id = registration.activity_id").
			Where(strings.Join(clauseKeys, " AND "), clauseValues...).Order("activities.id DESC").
			Limit(limit).Offset(offset).Scan(&activities).Error
	} else {
		if param.LeaderID != 0 {
			clauseKeys = append(clauseKeys, "leader_id = ?")
			clauseValues = append(clauseValues, param.LeaderID)
		}
		if param.Status != 0 {
			clauseKeys = append(clauseKeys, "status = ?")
			clauseValues = append(clauseValues, param.Status)
		}
		err := db.Table("activities").Select("activities.*").
			Where(strings.Join(clauseKeys, " AND "), clauseValues...).
			Count(&total).Error
		if err != nil {
			return total, nil, err
		}
		err = db.Table("activities").Select("activities.*").
			Where(strings.Join(clauseKeys, " AND "), clauseValues...).
			Order("activities.id DESC").
			Limit(limit).Offset(offset).Scan(&activities).Error
	}
	return total, activities, nil
}

//
func GetActivityWithRegisUsers() {

}

func UpdateActivityDO(ac *ActivityDO) error {
	db := config.GetDB()
	activity := ActivityDO{}
	err := db.Where("id = ?", ac.ID).First(&activity).Error
	if err != nil {
		return err
	}
	err = db.Model(&activity).Updates(
		ActivityDO{
			Title:                ac.Title,
			LeaderSay:            ac.LeaderSay,
			RouteDesc:            ac.RouteDesc,
			RoutePics:            ac.RoutePics,
			StartTime:            ac.StartTime,
			CollectionPlace:      ac.CollectionPlace,
			QrCode:               ac.QrCode,
			RegistrationDeadline: ac.RegistrationDeadline,
			CountLimit:           ac.CountLimit,
			Status:               ac.Status,
		}).Error
	if err != nil {
		return err
	}
	return nil
}

func QueryAndUpdateAcCurCount(acId uint, curCount int) error {
	db := config.GetDB()
	acDo := ActivityDO{}
	err := db.Where("id = ?", acId).First(&acDo).Error
	if err != nil {
		return err
	} else {
		err := db.Model(&acDo).Updates(
			map[string]interface{}{
				"cur_count": curCount,
			}).Error
		if err != nil {
			return err
		}
	}
	return err
}
